﻿//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2018 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.  

#ifdef RENDER_SNIPPET

#include <vector>

#include "PxPhysicsAPI.h"

#include "../SnippetRender/SnippetRender.h"
#include "../SnippetRender/SnippetCamera.h"

using namespace physx;

extern void initPhysics(bool interactive);
extern void stepPhysics(bool interactive);
extern void cleanupPhysics(bool interactive);
extern void keyPress(unsigned char key, const PxTransform& camera);
extern int abingo;
extern int ballNum;
extern int score;
extern int level;
namespace {
	Snippets::Camera* sCamera;
	void glWindowPos2i(GLint x, GLint y) {
		typedef void(__stdcall * ARBFUNC)(GLint x, GLint y);

		ARBFUNC glptr = 0;
		glptr = (ARBFUNC)wglGetProcAddress("glWindowPos2iARB");

		if (glptr)
			glptr(x, y);
		else
			printf("glWindowPos2iARB NOT exit\n");
	}

	void* bitmap_fonts[7] = { GLUT_BITMAP_9_BY_15,        GLUT_BITMAP_8_BY_13,
							 GLUT_BITMAP_TIMES_ROMAN_10, GLUT_BITMAP_TIMES_ROMAN_24,
							 GLUT_BITMAP_HELVETICA_10,   GLUT_BITMAP_HELVETICA_12,
							 GLUT_BITMAP_HELVETICA_18 };
	void print_bitmap_string(void* font, const char* s) {
		if (s && strlen(s)) {
			while (*s) {
				glutBitmapCharacter(font, *s);
				s++;
			}
		}
	}
	int TextOut(float x, float y, const char* cstr) {
		glWindowPos2i(x, y);
		print_bitmap_string(bitmap_fonts[1], cstr);
		return 1;
	}

	void display() {
		glColor3f(1.0, 0.0, 0.0);

		int fullbingo = 10;
		if (level == 3) {
			fullbingo = 14;
		}

		char buf[0x40] = { 0 };
		snprintf(buf, 0x40, "ball: %d/3 score: %d/%d level: %d/3", ballNum, abingo,
			fullbingo, level);
		TextOut(10, 490, buf);

		if ((ballNum == 0) && (score != 10) && ((level == 1) || (level == 2))) {
			snprintf(buf, 0x40, "FAILED");
			TextOut(250, 250, buf);
		}
		else if ((score == 10) && ((level == 1) || (level == 2))) {
			snprintf(buf, 0x40, "Enter 'N' to next level or Esc to exit");
			TextOut(125, 250, buf);
		}
		else if ((score == 14) && (level == 3)) {
			snprintf(buf, 0x40, "Win");
			TextOut(250, 250, buf);
		}
		else {
			return;
		}
	}
	void motionCallback(int x, int y) { sCamera->handleMotion(x, y); }

	void keyboardCallback(unsigned char key, int x, int y) {
		if (key == 27) exit(0);

		if (!sCamera->handleKey(key, x, y)) keyPress(key, sCamera->getTransform());
	}

	void mouseCallback(int button, int state, int x, int y) {
		sCamera->handleMouse(button, state, x, y);
	}

	void idleCallback() { glutPostRedisplay(); }

	void renderCallback() {
		stepPhysics(true);

		Snippets::startRender(sCamera->getEye(), sCamera->getDir());

		PxScene* scene;
		PxGetPhysics().getScenes(&scene, 1);
		PxU32 nbActors = scene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC |
			PxActorTypeFlag::eRIGID_STATIC);
		if (nbActors) {
			std::vector<PxRigidActor*> actors(nbActors);
			scene->getActors(
				PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC,
				reinterpret_cast<PxActor**>(&actors[0]), nbActors);

			Snippets::renderActors(&actors[0], static_cast<PxU32>(actors.size()),
				true, PxVec3(0.3f, 0.8f, 0.9f));
			Snippets::renderActors(&actors[1],
				static_cast<PxU32>(actors.size() - 1), true,
				PxVec3(0.3f, 0.8f, 0.9f));
		}
		display();
		Snippets::finishRender();
	}

	void exitCallback(void) {
		delete sCamera;
		cleanupPhysics(true);
	}

}  // namespace

void renderLoop() {
	// sCamera = new Snippets::Camera(PxVec3(50.0f, 50.0f, 50.0f),
	// PxVec3(-0.6f,-0.2f,-0.7f));
	sCamera = new Snippets::Camera(PxVec3(0.0f, 50.0f, 170.0f),
		PxVec3(0.0f, 0.0f, -1.0f));
	Snippets::setupDefaultWindow("Bolwing Game");
	Snippets::setupDefaultRenderState();

	glutIdleFunc(idleCallback);
	glutDisplayFunc(renderCallback);
	glutKeyboardFunc(keyboardCallback);
	glutMouseFunc(mouseCallback);
	glutMotionFunc(motionCallback);
	motionCallback(0, 0);
	atexit(exitCallback);

	initPhysics(true);
	glutMainLoop();
}
#endif
